/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "FpsCommonGLMaterialRenderer.h"
#include "CCommonGLDriver.h"
#include "EDriverFeatures.h"
#include "EVertexAttributes.h"
#include "SColor.h"
#include "CCommonGLHeaders.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OPENGL_ES_) || defined(_IRR_COMPILE_WITH_PS3_)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

using namespace irr;
using namespace video;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CCommonGLMaterialRenderer_ALPHA_TEST_NONTRANSPARENT::onSetMaterial(const SMaterial& material,
																				const SMaterial& lastMaterial,
																				bool resetAllRenderstates,
																				IMaterialRendererServices* services)
{
	Driver->disableTextures(1);
	Driver->setTexture(0, material.getTexture(0));
	Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);

	if (material.getMaterialType() != lastMaterial.getMaterialType() || resetAllRenderstates)
	{
		glEnable(GL_ALPHA_TEST);
		glAlphaFunc(GL_GREATER, 0.5f);
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CCommonGLMaterialRenderer_ALPHA_TEST_NONTRANSPARENT::onUnsetMaterial()
{
	glDisable(GL_ALPHA_TEST);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CCommonGLMaterialRenderer_ALPHA_TEST_NONTRANSPARENT::isTransparent() const
{
	return false;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

u32 CCommonGLMaterialRenderer_ALPHA_TEST_NONTRANSPARENT::getVertexAttributeMask() const
{
	return EVA_POSITION | EVA_COLOR0 | EVA_TEXCOORD0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CCommonGLMaterialRenderer_ADDITIVE_REPLACE_NONTRANSPARENT::onSetMaterial(const SMaterial& material,
																				const SMaterial& lastMaterial,
																				bool resetAllRenderstates,
																				IMaterialRendererServices* services)
{
	Driver->disableTextures(1);
	Driver->setTexture(0, material.getTexture(0));
	Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);

	if (material.getMaterialType() != lastMaterial.getMaterialType() || resetAllRenderstates)
	{
		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
		Driver->setTexEnvMode(GL_REPLACE);
		glEnable(GL_BLEND);
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CCommonGLMaterialRenderer_ADDITIVE_REPLACE_NONTRANSPARENT::onUnsetMaterial()
{
	glDisable(GL_BLEND);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CCommonGLMaterialRenderer_ADDITIVE_REPLACE_NONTRANSPARENT::isTransparent() const
{
	return false;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

u32 CCommonGLMaterialRenderer_ADDITIVE_REPLACE_NONTRANSPARENT::getVertexAttributeMask() const
{
	return EVA_POSITION | EVA_COLOR0 | EVA_TEXCOORD0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CCommonGLMaterialRenderer_ADDITIVE_MODULATE_NONTRANSPARENT::onSetMaterial(const SMaterial& material,
																				const SMaterial& lastMaterial,
																				bool resetAllRenderstates,
																				IMaterialRendererServices* services)
{
	Driver->disableTextures(1);
	Driver->setTexture(0, material.getTexture(0));
	Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);

	if (material.getMaterialType() != lastMaterial.getMaterialType() || resetAllRenderstates)
	{
		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
		Driver->setTexEnvMode(GL_MODULATE);
		glEnable(GL_BLEND);
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CCommonGLMaterialRenderer_ADDITIVE_MODULATE_NONTRANSPARENT::onUnsetMaterial()
{
	glDisable(GL_BLEND);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CCommonGLMaterialRenderer_ADDITIVE_MODULATE_NONTRANSPARENT::isTransparent() const
{
	return false;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

u32 CCommonGLMaterialRenderer_ADDITIVE_MODULATE_NONTRANSPARENT::getVertexAttributeMask() const
{
	return EVA_POSITION | EVA_COLOR0 | EVA_TEXCOORD0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CCommonGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_WITH_VERTEX_ALPHA::onSetMaterial(const SMaterial& material,
																							const SMaterial& lastMaterial,
																							bool resetAllRenderstates,
																							IMaterialRendererServices* services)
{
	Driver->disableTextures(1);
	Driver->setTexture(0, material.getTexture(0));
	Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);

	if (material.getMaterialType() != lastMaterial.getMaterialType() || resetAllRenderstates
		|| material.getMaterialTypeParam(0) != lastMaterial.getMaterialTypeParam(0) )
	{
		Driver->setTexEnvMode(GL_COMBINE);
		Driver->setCombineRGB(GL_MODULATE);
		Driver->setSourceRGB(0, GL_TEXTURE);
		Driver->setSourceRGB(1, GL_PREVIOUS);

		Driver->setCombineAlpha(GL_MODULATE);
		Driver->setSourceAlpha(0, GL_TEXTURE);
		Driver->setSourceAlpha(1, GL_PRIMARY_COLOR);

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);
		glEnable(GL_ALPHA_TEST);

		glAlphaFunc(GL_GREATER, material.getMaterialTypeParam(0));
	}
} 

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CCommonGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_WITH_VERTEX_ALPHA::onUnsetMaterial()
{
	glDisable(GL_ALPHA_TEST);
	glDisable(GL_BLEND);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CCommonGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_WITH_VERTEX_ALPHA::isTransparent() const
{
	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

u32 CCommonGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_WITH_VERTEX_ALPHA::getVertexAttributeMask() const
{
	return EVA_POSITION | EVA_COLOR0 | EVA_TEXCOORD0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CCommonGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF_BLEND::onSetMaterial(const SMaterial& material,
																	const SMaterial& lastMaterial,
																	bool resetAllRenderstates,
																	IMaterialRendererServices* services)
{
	Driver->disableTextures(1);
	Driver->setTexture(0, material.getTexture(0));
	Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);

	if (material.getMaterialType() != lastMaterial.getMaterialType() || resetAllRenderstates)
	{
#if defined(_IRR_COMPILE_WITH_PS3_)
		Driver->setTexEnvMode(GL_MODULATE);
#else
		Driver->setTexEnvMode(GL_COMBINE);
		Driver->setCombineRGB(GL_MODULATE);
		Driver->setSourceRGB(0, GL_TEXTURE);
		Driver->setSourceRGB(1, GL_PREVIOUS);

		Driver->setCombineAlpha(GL_REPLACE);
		Driver->setSourceAlpha(0, GL_TEXTURE);
#endif
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);

		glEnable(GL_ALPHA_TEST);
		glAlphaFunc(GL_GREATER, 0.5f);
	}
}

void CCommonGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF_BLEND::onUnsetMaterial()
{
	glDisable(GL_ALPHA_TEST);
	glDisable(GL_BLEND);
}

bool CCommonGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF_BLEND::isTransparent() const
{
	return true;
}

u32 CCommonGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF_BLEND::getVertexAttributeMask() const
{
	return EVA_POSITION | EVA_COLOR0 | EVA_TEXCOORD0;
}

void CCommonGLMaterialRenderer_AMBIENT_COLOR_TEXTURE_ALPHA::onSetMaterial(const SMaterial& material,
															const SMaterial& lastMaterial,
															bool resetAllRenderstates,
															IMaterialRendererServices* services)
{
	Driver->disableTextures(1);
	Driver->setTexture(0, material.getTexture(0));
	Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);

	if (material.getMaterialType() != lastMaterial.getMaterialType() || resetAllRenderstates)
	{
#if defined(_IRR_COMPILE_WITH_PS3_)
		Driver->setTexEnvMode(GL_MODULATE);
#else
		GLfloat	Color[4];
		SColor	matColor = material.getAmbientColor();

		Color[0] = matColor.R / 255.0f;
		Color[1] = matColor.G / 255.0f;
		Color[2] = matColor.B / 255.0f;
		Color[3] = matColor.A / 255.0f;

		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Color);

		Driver->setTexEnvMode(GL_COMBINE);
		Driver->setCombineRGB(GL_REPLACE);
		Driver->setSourceRGB(0, GL_CONSTANT);

		Driver->setCombineAlpha(GL_REPLACE);
		Driver->setSourceAlpha(0, GL_TEXTURE);

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);

#endif
	}
}

void CCommonGLMaterialRenderer_AMBIENT_COLOR_TEXTURE_ALPHA::onUnsetMaterial()
{
	glDisable(GL_BLEND);
}

bool CCommonGLMaterialRenderer_AMBIENT_COLOR_TEXTURE_ALPHA::isTransparent() const
{
	return false;
}

u32 CCommonGLMaterialRenderer_AMBIENT_COLOR_TEXTURE_ALPHA::getVertexAttributeMask() const
{
	return EVA_POSITION | EVA_TEXCOORD0;
}

void CCommonGLMaterialRenderer_TRANSPARENT_ADD_AMBIENT_COLOR::onSetMaterial(const SMaterial& material,
															const SMaterial& lastMaterial,
															bool resetAllRenderstates,
															IMaterialRendererServices* services)
{
	Driver->disableTextures(1);
	Driver->setTexture(0, material.getTexture(0));
	Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);

	if (material.getMaterialType() != lastMaterial.getMaterialType() || resetAllRenderstates)
	{
#if defined(_IRR_COMPILE_WITH_PS3_)
		Driver->setTexEnvMode(GL_MODULATE);
#else
		GLfloat	Color[4];
		SColor	matColor = material.getAmbientColor();

		Color[0] = matColor.R / 255.0f;
		Color[1] = matColor.G / 255.0f;
		Color[2] = matColor.B / 255.0f;
		Color[3] = matColor.A / 255.0f;

		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Color);

		Driver->setTexEnvMode(GL_COMBINE);
		Driver->setCombineRGB(GL_ADD);
		Driver->setSourceRGB(0, GL_TEXTURE);
		Driver->setSourceRGB(1, GL_CONSTANT);

		Driver->setCombineAlpha(GL_ADD);
		Driver->setSourceAlpha(0, GL_TEXTURE);
		Driver->setSourceAlpha(1, GL_CONSTANT);

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);
#endif
	}
}

void CCommonGLMaterialRenderer_TRANSPARENT_ADD_AMBIENT_COLOR::onUnsetMaterial()
{
	glDisable(GL_BLEND);
}

bool CCommonGLMaterialRenderer_TRANSPARENT_ADD_AMBIENT_COLOR::isTransparent() const
{
	return false;
}

u32 CCommonGLMaterialRenderer_TRANSPARENT_ADD_AMBIENT_COLOR::getVertexAttributeMask() const
{
	return EVA_POSITION | EVA_COLOR0 | EVA_TEXCOORD0;
}


void CCommonGLMaterialRenderer_TRANSPARENT_SUB_AMBIENT_COLOR::onSetMaterial(const SMaterial& material,
															const SMaterial& lastMaterial,
															bool resetAllRenderstates,
															IMaterialRendererServices* services)
{
	Driver->disableTextures(1);
	Driver->setTexture(0, material.getTexture(0));
	Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);

	if (material.getMaterialType() != lastMaterial.getMaterialType() || resetAllRenderstates)
	{
#if defined(_IRR_COMPILE_WITH_PS3_)
		Driver->setTexEnvMode(GL_MODULATE);
#else
		GLfloat	Color[4];
		SColor	matColor = material.getAmbientColor();

		Color[0] = matColor.R / 255.0f;
		Color[1] = matColor.G / 255.0f;
		Color[2] = matColor.B / 255.0f;
		Color[3] = matColor.A / 255.0f;

		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Color);

		Driver->setTexEnvMode(GL_COMBINE);
		Driver->setCombineRGB(GL_SUBTRACT);
		Driver->setSourceRGB(0, GL_TEXTURE);
		Driver->setSourceRGB(1, GL_CONSTANT);

		Driver->setCombineAlpha(GL_SUBTRACT);
		Driver->setSourceAlpha(0, GL_TEXTURE);
		Driver->setSourceAlpha(1, GL_CONSTANT);

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);
#endif
	}
}

void CCommonGLMaterialRenderer_TRANSPARENT_SUB_AMBIENT_COLOR::onUnsetMaterial()
{
	glDisable(GL_BLEND);
}

bool CCommonGLMaterialRenderer_TRANSPARENT_SUB_AMBIENT_COLOR::isTransparent() const
{
	return true;
}

u32 CCommonGLMaterialRenderer_TRANSPARENT_SUB_AMBIENT_COLOR::getVertexAttributeMask() const
{
	return EVA_POSITION | EVA_COLOR0 | EVA_TEXCOORD0;
}


void CCommonGLMaterialRenderer_AMBIENT_COLOR::onSetMaterial(const SMaterial& material,
															const SMaterial& lastMaterial,
															bool resetAllRenderstates,
															IMaterialRendererServices* services)
{
	Driver->disableTextures(1);
	Driver->setTexture(0, material.getTexture(0));
	Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);

	if (material.getMaterialType() != lastMaterial.getMaterialType() || resetAllRenderstates)
	{
#if defined(_IRR_COMPILE_WITH_PS3_)
		Driver->setTexEnvMode(GL_MODULATE);
#else
		GLfloat	Color[4];
		SColor	matColor = material.getAmbientColor();

		Color[0] = matColor.R / 255.0f;
		Color[1] = matColor.G / 255.0f;
		Color[2] = matColor.B / 255.0f;
		Color[3] = matColor.A / 255.0f;

		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Color);

		Driver->setTexEnvMode(GL_COMBINE);
		Driver->setCombineRGB(GL_REPLACE);
		Driver->setSourceRGB(0, GL_CONSTANT);

		Driver->setCombineAlpha(GL_REPLACE);
		Driver->setSourceAlpha(0, GL_CONSTANT);

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);

#endif
	}
}

void CCommonGLMaterialRenderer_AMBIENT_COLOR::onUnsetMaterial()
{
	glDisable(GL_BLEND);
}

bool CCommonGLMaterialRenderer_AMBIENT_COLOR::isTransparent() const
{
	return true;
}

u32 CCommonGLMaterialRenderer_AMBIENT_COLOR::getVertexAttributeMask() const
{
	return EVA_POSITION | EVA_TEXCOORD0;
}


void CCommonGLMaterialRenderer_AMBIENT_COLOR_DST_ALPHA::onSetMaterial(const SMaterial& material,
															const SMaterial& lastMaterial,
															bool resetAllRenderstates,
															IMaterialRendererServices* services)
{
	Driver->disableTextures(1);
	Driver->setTexture(0, material.getTexture(0));
	Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);

	if (material.getMaterialType() != lastMaterial.getMaterialType() || resetAllRenderstates)
	{
#if defined(_IRR_COMPILE_WITH_PS3_)
		Driver->setTexEnvMode(GL_MODULATE);
#else
		GLfloat	Color[4];
		SColor	matColor = material.getAmbientColor();

		Color[0] = matColor.R / 255.0f;
		Color[1] = matColor.G / 255.0f;
		Color[2] = matColor.B / 255.0f;
		Color[3] = matColor.A / 255.0f;

		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Color);

		Driver->setTexEnvMode(GL_COMBINE);
		Driver->setCombineRGB(GL_REPLACE);
		Driver->setSourceRGB(0, GL_CONSTANT);

		Driver->setCombineAlpha(GL_REPLACE);
		Driver->setSourceAlpha(0, GL_CONSTANT);

		glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
		glEnable(GL_BLEND);
#endif
	}
}

void CCommonGLMaterialRenderer_AMBIENT_COLOR_DST_ALPHA::onUnsetMaterial()
{
	glDisable(GL_BLEND);
}

bool CCommonGLMaterialRenderer_AMBIENT_COLOR_DST_ALPHA::isTransparent() const
{
	return false;
}

u32 CCommonGLMaterialRenderer_AMBIENT_COLOR_DST_ALPHA::getVertexAttributeMask() const
{
	return EVA_POSITION;
}


void CCommonGLMaterialRenderer_TRANSPARENT_ADD_COLOR_SUB_ALPHA::onSetMaterial(const SMaterial& material,
															const SMaterial& lastMaterial,
															bool resetAllRenderstates,
															IMaterialRendererServices* services)
{
	Driver->disableTextures(1);
	Driver->setTexture(0, material.getTexture(0));
	Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);

	if (material.getMaterialType() != lastMaterial.getMaterialType() || resetAllRenderstates)
	{
#if defined(_IRR_COMPILE_WITH_PS3_)
		Driver->setTexEnvMode(GL_MODULATE);
#else
		GLfloat	Color[4];
		SColor	matColor = material.getAmbientColor();

		Color[0] = matColor.R / 255.0f;
		Color[1] = matColor.G / 255.0f;
		Color[2] = matColor.B / 255.0f;
		Color[3] = matColor.A / 255.0f;

		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Color);

		Driver->setTexEnvMode(GL_COMBINE);
		Driver->setCombineRGB(GL_ADD);
		Driver->setSourceRGB(0, GL_TEXTURE);
		Driver->setSourceRGB(1, GL_CONSTANT);

		Driver->setCombineAlpha(GL_SUBTRACT);
		Driver->setSourceAlpha(0, GL_TEXTURE);
		Driver->setSourceAlpha(1, GL_CONSTANT);

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);
#endif
	}
}

void CCommonGLMaterialRenderer_TRANSPARENT_ADD_COLOR_SUB_ALPHA::onUnsetMaterial()
{
	glDisable(GL_BLEND);
}

bool CCommonGLMaterialRenderer_TRANSPARENT_ADD_COLOR_SUB_ALPHA::isTransparent() const
{
	return true;
}

u32 CCommonGLMaterialRenderer_TRANSPARENT_ADD_COLOR_SUB_ALPHA::getVertexAttributeMask() const
{
	return EVA_POSITION | EVA_COLOR0 | EVA_TEXCOORD0;
}


#endif // _IRR_COMPILE_WITH_OPENGL_ || _IRR_COMPILE_WITH_OPENGL_ES_